using BCrypt.Net;
using CR.Domain.Entities;
using CR.ErrorCode;
using CR.Infrastructure.Repositories;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Configuration;
using System;
using System.Security.Claims;
using System.Threading.Tasks;

namespace CR.API.Services
{
    /// <summary>
    /// 用户服务实现
    /// </summary>
    public class UserService : IUserService
    {
        private readonly IUserRepository _userRepository;
        private readonly IJwtService _jwtService;
        private readonly ICaptchaService _captchaService;
        private readonly IHttpContextAccessor _httpContextAccessor;
        private readonly IConfiguration _configuration;
        
        // 配置
        private readonly int _maxFailedAttempts;
        private readonly int _lockoutMinutes;
        private readonly bool _requireCaptcha;

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="userRepository">用户仓储</param>
        /// <param name="jwtService">JWT服务</param>
        /// <param name="captchaService">验证码服务</param>
        /// <param name="httpContextAccessor">HTTP上下文访问器</param>
        /// <param name="configuration">配置</param>
        public UserService(
            IUserRepository userRepository,
            IJwtService jwtService,
            ICaptchaService captchaService,
            IHttpContextAccessor httpContextAccessor,
            IConfiguration configuration)
        {
            _userRepository = userRepository;
            _jwtService = jwtService;
            _captchaService = captchaService;
            _httpContextAccessor = httpContextAccessor;
            _configuration = configuration;
            
            // 从配置中获取设置
            _maxFailedAttempts = int.Parse(_configuration["Security:MaxFailedAttempts"] ?? "5");
            _lockoutMinutes = int.Parse(_configuration["Security:LockoutMinutes"] ?? "30");
            _requireCaptcha = bool.Parse(_configuration["Security:RequireCaptcha"] ?? "true");
        }

        /// <summary>
        /// 用户登录
        /// </summary>
        /// <param name="username">用户名</param>
        /// <param name="password">密码</param>
        /// <param name="captchaId">验证码ID</param>
        /// <param name="captchaCode">验证码</param>
        /// <returns>登录结果</returns>
        public async Task<ApiResult<string>> LoginAsync(string username, string password, string captchaId, string captchaCode)
        {
            // 验证参数
            if (string.IsNullOrEmpty(username) || string.IsNullOrEmpty(password))
            {
                return ApiResult<string>.Fail(ApiEnums.ParameterError, "用户名或密码不能为空");
            }

            // 验证验证码
            if (_requireCaptcha)
            {
                if (string.IsNullOrEmpty(captchaId) || string.IsNullOrEmpty(captchaCode))
                {
                    return ApiResult<string>.Fail(ApiEnums.CaptchaRequired, "验证码不能为空");
                }

                bool isCaptchaValid = await _captchaService.ValidateCaptchaAsync(captchaId, captchaCode);
                if (!isCaptchaValid)
                {
                    return ApiResult<string>.Fail(ApiEnums.CaptchaError, "验证码错误");
                }
            }

            // 查找用户
            var user = await _userRepository.GetByUsernameAsync(username);
            if (user == null)
            {
                return ApiResult<string>.Fail(ApiEnums.UserNotFound, "用户不存在");
            }

            // 检查用户是否被锁定
            if (user.IsLockedOut())
            {
                var remainingMinutes = (user.LockoutEnd.Value - DateTime.Now).Minutes + 1;
                return ApiResult<string>.Fail(ApiEnums.UserLocked, $"账号已锁定，请{remainingMinutes}分钟后再试");
            }

            // 验证密码
            bool isPasswordValid = BCrypt.Net.BCrypt.Verify(password, user.PasswordHash);
            if (!isPasswordValid)
            {
                // 增加登录失败次数，如果达到上限则锁定账号
                bool isLocked = user.IncrementAccessFailedCount(_maxFailedAttempts, _lockoutMinutes);
                await _userRepository.UpdateAsync(user);

                if (isLocked)
                {
                    return ApiResult<string>.Fail(ApiEnums.UserLocked, $"密码错误次数过多，账号已锁定{_lockoutMinutes}分钟");
                }

                int remainingAttempts = _maxFailedAttempts - user.AccessFailedCount;
                return ApiResult<string>.Fail(ApiEnums.PasswordError, $"密码错误，还有{remainingAttempts}次机会");
            }

            // 密码正确，重置登录失败次数
            user.ResetAccessFailedCount();
            user.LastLoginTime = DateTime.Now;
            await _userRepository.UpdateAsync(user);

            // 生成JWT令牌
            string token = _jwtService.GenerateToken(user);

            return ApiResult<string>.Success(token);
        }

        /// <summary>
        /// 注册用户
        /// </summary>
        /// <param name="user">用户信息</param>
        /// <param name="password">密码</param>
        /// <returns>注册结果</returns>
        public async Task<ApiResult<User>> RegisterAsync(User user, string password)
        {
            // 验证参数
            if (user == null || string.IsNullOrEmpty(password))
            {
                return ApiResult<User>.Fail(ApiEnums.ParameterError, "用户信息或密码不能为空");
            }

            // 检查用户名是否已存在
            if (await _userRepository.UsernameExistsAsync(user.Username))
            {
                return ApiResult<User>.Fail(ApiEnums.UserExists, "用户名已存在");
            }

            // 检查邮箱是否已存在
            if (!string.IsNullOrEmpty(user.Email) && await _userRepository.EmailExistsAsync(user.Email))
            {
                return ApiResult<User>.Fail(ApiEnums.EmailExists, "邮箱已存在");
            }

            // 哈希密码
            user.PasswordHash = BCrypt.Net.BCrypt.HashPassword(password);
            
            // 设置默认值
            user.CreatedAt = DateTime.Now;
            user.AccessFailedCount = 0;
            user.IsLocked = false;
            user.IsActive = true;

            // 保存用户
            await _userRepository.AddAsync(user);

            // 清除敏感信息
            user.PasswordHash = null;

            return ApiResult<User>.Success(user);
        }

        /// <summary>
        /// 获取用户信息
        /// </summary>
        /// <param name="userId">用户ID</param>
        /// <returns>用户信息</returns>
        public async Task<ApiResult<User>> GetUserAsync(int userId)
        {
            var user = await _userRepository.GetByIdAsync(userId);
            if (user == null)
            {
                return ApiResult<User>.Fail(ApiEnums.UserNotFound, "用户不存在");
            }

            // 清除敏感信息
            user.PasswordHash = null;

            return ApiResult<User>.Success(user);
        }

        /// <summary>
        /// 修改密码
        /// </summary>
        /// <param name="userId">用户ID</param>
        /// <param name="oldPassword">旧密码</param>
        /// <param name="newPassword">新密码</param>
        /// <returns>修改结果</returns>
        public async Task<ApiResult> ChangePasswordAsync(int userId, string oldPassword, string newPassword)
        {
            // 验证参数
            if (string.IsNullOrEmpty(oldPassword) || string.IsNullOrEmpty(newPassword))
            {
                return ApiResult.Fail(ApiEnums.ParameterError, "旧密码或新密码不能为空");
            }

            // 查找用户
            var user = await _userRepository.GetByIdAsync(userId);
            if (user == null)
            {
                return ApiResult.Fail(ApiEnums.UserNotFound, "用户不存在");
            }

            // 验证旧密码
            bool isPasswordValid = BCrypt.Net.BCrypt.Verify(oldPassword, user.PasswordHash);
            if (!isPasswordValid)
            {
                return ApiResult.Fail(ApiEnums.PasswordError, "旧密码错误");
            }

            // 更新密码
            user.PasswordHash = BCrypt.Net.BCrypt.HashPassword(newPassword);
            await _userRepository.UpdateAsync(user);

            return ApiResult.Success("密码修改成功");
        }

        /// <summary>
        /// 解锁用户
        /// </summary>
        /// <param name="userId">用户ID</param>
        /// <returns>解锁结果</returns>
        public async Task<ApiResult> UnlockUserAsync(int userId)
        {
            // 查找用户
            var user = await _userRepository.GetByIdAsync(userId);
            if (user == null)
            {
                return ApiResult.Fail(ApiEnums.UserNotFound, "用户不存在");
            }

            // 解锁用户
            user.Unlock();
            await _userRepository.UpdateAsync(user);

            return ApiResult.Success("用户解锁成功");
        }

        /// <summary>
        /// 获取当前用户
        /// </summary>
        /// <returns>当前用户</returns>
        public async Task<User?> GetCurrentUserAsync()
        {
            var httpContext = _httpContextAccessor.HttpContext;
            if (httpContext == null || httpContext.User == null || !httpContext.User.Identity!.IsAuthenticated)
            {
                return null;
            }

            var userIdClaim = httpContext.User.FindFirst(ClaimTypes.NameIdentifier);
            if (userIdClaim == null || !int.TryParse(userIdClaim.Value, out int userId))
            {
                return null;
            }

            var user = await _userRepository.GetByIdAsync(userId);
            
            // 清除敏感信息
            if (user != null)
            {
                user.PasswordHash = null;
            }
            
            return user;
        }
    }
} 